import { ValidationAcceptor } from "langium";
import { BlockItem, CompUnit, Exp, FuncDef, FuncRParams, FunctionCall, Stmtelif, Stmtwhile } from "./generated/ast.js";

export class FuncValidator {
    // 函数悬停提示
    hoverTipsFunc(e: FuncRParams, accept: ValidationAcceptor): void {
        let params = e.funcname.ref?.funcFparam;
        let paramArray: String[] = [];
        params?.forEach(e => {
            paramArray.push(e.$cstNode?.text!);
        });
        accept("hint", `(方法) (${paramArray.join(", ")}): ${e.funcname.ref?.functype}。`, { node: e, property: undefined });
    }

    // 检查未定义的函数
    checkFunctionDeclared(funcCall: FunctionCall, accept: ValidationAcceptor): void {
        if (!funcCall.funcname.ref) {
            accept('error', `调用了未定义的函数 '${funcCall.funcname.$refText}'。`, { node: funcCall, property: 'funcname' });
        }
    }

    // 检查函数名是否唯一
    checkUniqueFuncName(compUnit: CompUnit, accept: ValidationAcceptor): void {
        const funcNames = new Set<string>();
        for (const func of compUnit.function) {
            if (funcNames.has(func.name)) {
                accept('error', `函数名 '${func.name}' 已经定义过。`, { node: func, property: 'name' });
            } else {
                funcNames.add(func.name);
            }
        }
    }

    //非法break
    checkBreakContinueInNonLoopBlocks(funcDef: FuncDef, accept: ValidationAcceptor): void {
        let isInLoop = false;

        const checkBlock = (block: BlockItem): void => {
            if (block.hasOwnProperty('blockstmt')) {
                for (const stmt of block.blockstmt) {
                    if (stmt.$type === 'Stmtwhile') {
                        isInLoop = true;
                        const innerBlock = (stmt as Stmtwhile).whilestmt as BlockItem;
                        if (innerBlock.$type === 'BlockItem') {
                            checkBlock(innerBlock);
                        }
                        isInLoop = false;
                    } else if (stmt.$type === 'Stmtelif') {
                        const ifstmt = stmt as Stmtelif;
                        if (ifstmt.hasOwnProperty('ifstmt')) {
                            const innerBlock = (ifstmt.ifstmt as BlockItem);
                            if (innerBlock.$type === 'BlockItem') {
                                checkBlock(innerBlock);
                            }
                        }
                    } else if (stmt.$type === 'Stmtbreak' || stmt.$type === 'Stmtcontinue') {
                        if (!isInLoop) {
                            accept('error', `非循环块中使用了 ${stmt.$type} 语句。`, { node: stmt, property: undefined });
                        }
                    } else if (stmt.$type === 'BlockItem') {
                        checkBlock(stmt as BlockItem);
                    }
                }
            }
        };

        if (funcDef.hasOwnProperty('block')) {
            checkBlock(funcDef.block as BlockItem);
        }
    }


    // 检查函数参数不匹配
    checkFunctionParameterMismatch(func: FuncRParams, accept: ValidationAcceptor): void {
        let declaredParams = func.funcname.ref?.funcFparam;
        let declaredParamArray: String[] = [];
        let callParamArray = func.funcRparams;

        // 收集声明的参数
        declaredParams?.forEach(param => {
            declaredParamArray.push(param.$cstNode?.text!);
        });

        // 检查参数个数是否匹配
        if (declaredParamArray.length !== callParamArray.length) {
            accept('error', `参数个数不匹配。预期 ${declaredParamArray.length} 个参数，但实际调用时传递了 ${callParamArray.length} 个参数。`, { node: func });
        }
    }

    // 检查函数返回类型
    checkFunctionReturnType(func: FuncDef, accept: ValidationAcceptor): void {
        // 函数返回值
        const returnType = func.functype
        const block = func.block as BlockItem
        let hasReturn = false
        let actuallReturnType = null
        block.blockstmt?.forEach(b => {
            if (b.$type === "Stmtreturn") {
                actuallReturnType = b.tobereturn as Exp
                hasReturn = true
            }
        })
        // 检查有返回值的函数，若没有 return 语句则报错
        if (!hasReturn && returnType !== "void") {
            return accept('error', `有返回值: ${returnType} 的函数缺少 return 语句。`, { node: func });
        }
        // 检查有返回值的函数，若 return为空 则报错
        if (hasReturn && returnType !== "void") {
            if (actuallReturnType !== null) {
                let t = actuallReturnType as Exp
                if (!t?.$cstNode?.text)
                    return accept('error', `有返回值: ${returnType} 的函数不应返回为空。`, { node: block });
            }
        }
        // 检查无返回值的函数是否错误的 return 非空
        if (hasReturn && returnType === "void") {
            if (actuallReturnType !== null && actuallReturnType !== undefined) {
                let t = actuallReturnType as Exp
                return accept('error', `void 函数不应存在非空返回值${t.$cstNode?.text}。`, { node: actuallReturnType });
            }
        }
    }

    // 检查变量定义类型是否符合返回类型
    checkDefTypeMatchFuncReturnType(funcFparam: FuncRParams, accept: ValidationAcceptor): void {
        // 所调用的函数的返回类型
        let tarReturnType = funcFparam.funcname.ref?.functype
        if (tarReturnType === "void")
            accept('error', `不能将void类型变量参与运算或用于赋值`, { node: funcFparam.$container?.$cstNode?.astNode! });
    }
}